package cy.mybatis.genui;

import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 数据库查询结果POJO转换
 * @author chenyl
 */
public class CyUtil{
	private static final char SEPARATOR = '_'; 
	public static <T> T toBean(Class<T> clazz,ResultSet rs) throws Exception{
		if(!rs.next()){
			return null;
		}
		T t = clazz.newInstance();
		ResultSetMetaData rsmd = rs.getMetaData();
		int len = rsmd.getColumnCount();
		Map<String,Method> mm = getSetMethod(clazz);
		for(int i = 1; i <= len; i++){
			String label = rsmd.getColumnLabel(i);
			Method m = mm.get(lineToCamel(label, true));
			if(m!=null){
				m.invoke(t, rs.getObject(label));
			}
		}
		return t;
	}
	
	public static Map<String, Object> toMap(ResultSet rs) throws Exception{
		Map<String, Object> map = new HashMap<String, Object>();
		if(!rs.next()){
			return null;
		}
		ResultSetMetaData rsmd = rs.getMetaData();
		int len = rsmd.getColumnCount();
		for(int i = 1; i <= len; i++){
			String label = rsmd.getColumnLabel(i);
			map.put(lineToCamel(label,false), rs.getObject(label));
		}
		return map;
	}
	
	public static Map<String, Object> toStrMap(ResultSet rs) throws Exception{
		Map<String, Object> map = new HashMap<String, Object>();
		if(!rs.next()){
			return null;
		}
		ResultSetMetaData rsmd = rs.getMetaData();
		int len = rsmd.getColumnCount();
		for(int i = 1; i <= len; i++){
			String label = rsmd.getColumnLabel(i);
			Object obj = rs.getObject(label);
			if(obj instanceof java.sql.Timestamp){
				java.sql.Timestamp ts = (java.sql.Timestamp)obj;
				SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				map.put(lineToCamel(label,false), format.format(new Date(ts.getTime())));
			}else if(obj instanceof java.util.Date){
				SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				map.put(lineToCamel(label,false), format.format((Date)obj));
			}else{
				map.put(lineToCamel(label,false), rs.getString(label));
			}
		}
		return map;
	}
	
	public static <T> List<T> toList(Class<T> clazz,ResultSet rs) throws Exception{
		List<T> list = new ArrayList<T>();
		while(true){
			T t = toBean(clazz, rs);
			if(t==null){
				break;
			}
			list.add(t);
		}
		return list;
	}
	
	public static List toList(ResultSet rs) throws Exception {
		List list = new ArrayList();
		while(true){
			Map m = toMap(rs);
			if(m==null){
				break;
			}
			list.add(m);
		}
		return list;
	}
	
	public static List toStrList(ResultSet rs) throws Exception{
		List list = new ArrayList();
		while(true){
			Map m = toStrMap(rs);
			if(m==null){
				break;
			}
			list.add(m);
		}
		return list;
	}
	
	private static Map<String,Method> getSetMethod(Class<?> clazz){
		Map<String,Method> map = new HashMap<String, Method>();
		Method[] array = clazz.getMethods();
		int len = array.length;
		for(int i =0 ; i < len; i++){
			Method m = array[i];
			if(m.getName().startsWith("set")&& m.getParameterTypes().length==1){
				map.put(m.getName().substring(3), m);
			}
		}
		return map;
	}

	public static String lineToCamel(String str,boolean firstUpperCase){
		if(str==null || str.length() == 0){
			return str;
		}
		str = str.toLowerCase();
		int len = str.length();
		StringBuffer sb = new StringBuffer();
		boolean upperCase = firstUpperCase;
		for(int i = 0; i < len; i++){
			char c = str.charAt(i);
			if(c==SEPARATOR){
				upperCase = true;
				continue;
			}
			if(upperCase){
				sb.append(Character.toUpperCase(str.charAt(i)));
				upperCase = false;
			}else{
				sb.append(str.charAt(i));
			}
		}
		return sb.toString();
	}

	public static String camelToLine(String str) throws Exception{
		if(str==null || str.length() == 0){
			return str;
		}
		StringBuilder sb = new StringBuilder();  
		boolean nextIsUpperCase = false;  
		int len = str.length();
		for(int i = 0; i < len; i++){
			char c = str.charAt(i);
			if(i<len-1){
				nextIsUpperCase = Character.isUpperCase(str.charAt(i+1));
			}else{
				nextIsUpperCase = false;
			}
			if(Character.isLowerCase(c)&& nextIsUpperCase){
				if(i<len-1){
					sb.append(c).append(SEPARATOR).append(Character.toLowerCase(str.charAt(i+1)));
					i++;
				}else{
					sb.append(c).append(SEPARATOR);
				}
				
			}else if(Character.isUpperCase(c)&& !nextIsUpperCase && i > 0){
				sb.append(SEPARATOR).append(Character.toLowerCase(str.charAt(i)));
			}else{
				sb.append(Character.toLowerCase(c));
			}
			
		}
		return sb.toString();
	}
	
	
	public static void close(ResultSet rs) throws SQLException {
		if(rs!=null){
			rs.close();
		}
	}
	
	public static void close(Connection conn) throws SQLException{
		if(conn!=null){
			conn.close();
		}
	}
        
        public static List<String> getTableList(String driverPath,String driverName,String connUrl,String user,String password,String sql) throws Exception{
            URL url = new URL("file:/"+driverPath);
            ClassLoader classLoader = new URLClassLoader(new URL[]{url});  
            Object clazz = classLoader.loadClass(driverName).newInstance();
            Properties prop = new Properties();
            prop.setProperty("user",user);
            prop.setProperty("password",password);
            Driver myDriver = (Driver)clazz;
            Connection con = myDriver.connect(connUrl,prop);
            //Connection con = DriverManager.getConnection(connUrl,user,password);
            Statement stmt = con.createStatement();
            ResultSet rs=stmt.executeQuery(sql);
            List<Map> list = CyUtil.toList(rs);
            CyUtil.close(rs);
            CyUtil.close(con);
            List<String> resList = new ArrayList<String>();
            if(list==null){
               return resList; 
            }
            for(Map map : list ){
                resList.add((String)map.values().toArray()[0]);
            }
            return resList;
        }
        
        /**
         * 加载应用外面的数据库驱动获取连接
         * @param driverPath 驱动包路径
         * @param driverName 驱动类名
         * @param connUrl 数据库连接地址
         * @param user 用户名
         * @param password 密码
         * @return
         * @throws Exception 
         */
        public static Connection getConnection(String driverPath,String driverName,String connUrl,String user,String password) throws Exception{
            URL url = new URL("file:/"+driverPath);
            ClassLoader classLoader = new URLClassLoader(new URL[]{url});  
            Object clazz = classLoader.loadClass(driverName).newInstance();
            Properties prop = new Properties();
            prop.setProperty("user",user);
            prop.setProperty("password",password);
            Driver myDriver = (Driver)clazz;
            Connection conn = myDriver.connect(connUrl,prop);
            return conn;
        }
    public static void writeLog(Class clazz, Exception ex){
        Logger.getLogger(clazz.getName()).log(Level.SEVERE, null, ex);
    }

}
